<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    *:before,
    *:after {
      -webkit-box-sizing: border-box;
      -moz-box-sizing: border-box;
      box-sizing: border-box;
    }

    html,
    body,
    ul {
      height: 100%;
      font-family: Helvetica;
      margin: 0;
      padding: 0
    }

    li {
      border-bottom: 1px solid #E0E0E0;
      font-size: 20px;
      font-weight: bold;
      list-style: none outside none;
      margin: 0;
      padding: 8px 0 8px 10px;
      position: relative;
      -webkit-transition: opacity .75s ease-in;
      background: #fff;
    }

    #window {
      height: 100%;
      overflow: hidden;
    }

    #content {
      position: absolute;
      top: 0;
      background: linear-gradient(#2A65E3, #3875f8);
      width: 100%;
      top: 0;
      transition: transform .3s linear;
      height: 100vh;
    }

    #list {
      overflow-x: hidden;
    }

    #pull_to_refresh,
    #refreshing {
      line-height: 50px;
      text-align: center;
      background: #2A65E3;
      color: #ffffff;
    }

    .img {
      height: 70px;
      width: 70px;
      background: #cccccc;
    }

    .line-top,
    .line-mid,
    .line-bottom {
      height: 8px;
      width: 70%;
      margin-left: 92px;
      position: absolute;
      background-color: #cccccc;
    }

    .line-top {
      top: 22px;
      width: 100px;
    }

    .line-mid {
      bottom: 40px;
    }

    .line-bottom {
      width: 65%;
      bottom: 26px;
    }
  </style>
</head>

<body>
  <div id="window">
    <div id="pull_to_refresh">Pull and release to refresh</div>
    <div id="refreshing" style="display: none;">Refreshing</div>
    <div id="content">
      <ul id="list">
        <li class="item">
          <div class="img"></div>
          <span class="line-top"></span>
          <span class="line-mid"></span>
          <span class="line-bottom"></span>
        </li>
        <li class="item">
          <div class="img"></div>
          <span class="line-top"></span>
          <span class="line-mid"></span>
          <span class="line-bottom"></span>
        </li>
        <li class="item">
          <div class="img"></div>
          <span class="line-top"></span>
          <span class="line-mid"></span>
          <span class="line-bottom"></span>
        </li>
        <li class="item">
          <div class="img"></div>
          <span class="line-top"></span>
          <span class="line-mid"></span>
          <span class="line-bottom"></span>
        </li>
        <li class="item">
          <div class="img"></div>
          <span class="line-top"></span>
          <span class="line-mid"></span>
          <span class="line-bottom"></span>
        </li>
        <li class="item">
          <div class="img"></div>
          <span class="line-top"></span>
          <span class="line-mid"></span>
          <span class="line-bottom"></span>
        </li>
        <li class="item">
          <div class="img"></div>
          <span class="line-top"></span>
          <span class="line-mid"></span>
          <span class="line-bottom"></span>
        </li>
        <li class="item">
          <div class="img"></div>
          <span class="line-top"></span>
          <span class="line-mid"></span>
          <span class="line-bottom"></span>
        </li>
        <li class="item">
          <div class="img"></div>
          <span class="line-top"></span>
          <span class="line-mid"></span>
          <span class="line-bottom"></span>
        </li>
        <li class="item">
          <div class="img"></div>
          <span class="line-top"></span>
          <span class="line-mid"></span>
          <span class="line-bottom"></span>
        </li>
        <li class="item">
          <div class="img"></div>
          <span class="line-top"></span>
          <span class="line-mid"></span>
          <span class="line-bottom"></span>
        </li>
      </ul>
    </div>
  </div>
  <script>
    let $ = (selector, context) => {
      return new Init(selector, context);
    };

    function Init(selector, context) {
      this.initProps(selector, context);
    }

    Init.eventDep = {};

    $.isDOM = (el) => {
      let elTypes = [Node.ELEMENT_NODE, Node.DOCUMENT_NODE];
      return elTypes.includes(el.nodeType);
    };

    $.each = (targets, callback) => {
      targets = Array.from(targets);
      let i = 0;
      let flag = true;
      while (i < (targets.length || 0)) {
        let el = targets[i];
        typeof callback == 'function' && (flag = callback.call(el, el, i));
        if (flag === false) { break; }
        i++;
      }
      return targets;
    }

    $.query = (selector, oParent = document) => {
      let els = Array.from(selector);
      if ($.isDOM(selector)) {
        return [selector];
      }
      if (typeof selector == 'string') {
        return oParent.querySelectorAll(selector);
      }
      return els;
    };

    $.contains = (targetEl, els) => {
      let isContains = false;
      $.each(targetEl, target => {
        $.each(els, el => {
          if (target.contains(el)) {
            isContains = true;
            return false;
          }
        });
        if (isContains) { return false }
      })
      return isContains;
    }

    $.prototype = Object.create(Array.prototype);

    let c = null;

    Object.assign($.prototype, {
      constructor: $,
      initProps(selector, context) {
        let els = $.query(selector, context);
        Object.assign(this, els);
        this.length = els.length || 0;
        this.context = context || document;
      },
      find(selector) {
        let doms = [];
        this.each(el => {
          let els = $.query(selector, el);
          doms.push(...els);
        });
        return $(doms);
      },
      each(callback) {
        return $.each(this, callback);
      },
      evtListener(eventName, handler) {
        return this.each(el => {
          let callback = e => typeof handler == 'function' && handler.call(el, e);
          let events = Init.eventDep[el] || (Init.eventDep[el] = {});
          (events[eventName] || (events[eventName] = [])).push(callback);
          el.addEventListener(eventName, callback, false);
        });
      },
      off(eventName) {
        return this.each(el => {
          let deps = Init.eventDep[el];
          let events = deps[eventName];
          if (deps && events && events.length > 0) {
            $.each(events, handler => {
              el.removeEventListener(eventName, handler, false);
            })
          }
        })
      },
      contains(nodes) {
        return $.contains(this, nodes);
      },
      on(eventName, selector, callback) {
        return this.evtListener(eventName, e => {
          let $self = $(e.target);
          let $target = this.find(selector);
          if ($target.contains($self)) {
            typeof callback == 'function' && callback.call($self[0], e);
          }
        });
      }
    })

    Init.prototype = $.prototype;
  </script>
  <script>
    let drag = ($container) => {
      let $doc = $(document);
      let mouserStartY = 0;
      let dragResistance = 0.16; // 拖拽抗力，胡可定律k
      let y = 0;
      let maxDistance = 60;
      let minDistance = 30;
      $container.evtListener('touchstart', e => {
        //e.preventDefault();
        e = e.touches[0];
        mouserStartY = e.clientY;
        moveEvt();
      });
      let moveEvt = () => {
        $doc.evtListener('touchmove', e => {
          e = e.touches[0];
          if (e.clientY < mouserStartY) { return }
          y = Math.abs(mouserStartY - e.clientY) * dragResistance;
          y > maxDistance && (y = maxDistance);
          $container[0].style.top = y + 'px';
          $container[0].style['transition'] = ''
        })
        $doc.evtListener('touchend', e => {
          e = e.touches[0];
          $doc.off('touchmove');
          $doc.off('touchend');
          $doc.off('transitionend');
          if (y > minDistance) {
            isRefresh = true;
            console.log('刷新成功，事件')
          }
          $container[0].style.top = '0';
          $container[0].style['transition'] = '.3s'
        });
        $container.evtListener('transitionend', () => {
          isRefresh = false;
        });
      };
    }

    let $c = $('#content');
    drag($c);
  </script>
</body>

</html>